package components.editor
{
	import UIFree.ObjectEvent;
	import UIFree.uif_component;
	import UIFree.uif_ecomponent;
	
	import UIUtils.uif_util;
	import UIUtils.uif_utilBitmap;
	
	import classes.Commands.c_applyHistoryData;
	import classes.Commands.c_cropCommand;
	import classes.Commands.c_deleteCommand;
	import classes.Commands.c_insertBitmapCommand;
	import classes.Commands.c_linkCommand;
	import classes.c_cursors;
	import classes.c_events;
	import classes.c_uiEvents;
	
	import components.c_component;
	import components.c_pcomponent;
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.BlendMode;
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.text.TextField;
	import flash.text.TextFieldType;
	import flash.ui.Keyboard;
	
	public class c_dragRect extends c_baseElement {
		public static const HANDLESIZE	: Number = 8;
		public static const SIZESTYLE	: String = 'handleSize';
		public static const ROLLSTYLE	: String = 'handleRoll';
		public static const HANDLEDATA	: Array = [
			[0, 0, HANDLESIZE * 4, 'ROLL', ROLLSTYLE, c_cursors.ROLL],
			[1, 0, HANDLESIZE * 4, 'ROLL', ROLLSTYLE, c_cursors.ROLL],
			[1, 1, HANDLESIZE * 4, 'ROLL', ROLLSTYLE, c_cursors.ROLL],
			[0, 1, HANDLESIZE * 4, 'ROLL', ROLLSTYLE, c_cursors.ROLL],
			
			[0.5, 0, HANDLESIZE, 0, SIZESTYLE, c_cursors.VARROW],
			[1, 0, HANDLESIZE, 1, SIZESTYLE, c_cursors.BRARROW],
			[1, 0.5, HANDLESIZE, 2, SIZESTYLE, c_cursors.HARROW],
			[1, 1, HANDLESIZE, 3, SIZESTYLE, c_cursors.LBARROW],
			[0.5, 1, HANDLESIZE, 4, SIZESTYLE, c_cursors.VARROW],
			[0, 1, HANDLESIZE, 5, SIZESTYLE, c_cursors.BRARROW],
			[0, 0.5, HANDLESIZE, 6, SIZESTYLE, c_cursors.HARROW],
			[0, 0, HANDLESIZE, 7, SIZESTYLE, c_cursors.LBARROW]
		]
		public static const MINSIZE: int = 10;
			
		private var _rect				: c_rect;
		private var _handles			: c_pcomponent;
		private var _link				: c_baseElement;
		private var _linkSize			: Point;
		private var _mySet				: Boolean;
		private var _prevRestoreData	: Object;
		private var _look				: Boolean;
		private var _nodragMode			: Boolean;
		
		public function c_dragRect(parent:uif_component) {
			super(parent);
			visible 			= false;
			_nodragMode			= false;
		}
		
		public function get link(): c_baseElement {
			return _link;
		}
		
		public function set link(a_link: c_baseElement): void {
			if (!look) linkComponent(a_link);
		}
		
		public function get look(): Boolean {
			return _look;
		}
		
		public function set look(a_look: Boolean): void {
			_look 						= a_look;
			_handles.visible 			= !a_look;
			_rect.cursorName 			= a_look?'':c_cursors.MOVE;
			_rect.doubleClickEnabled 	= !a_look;
		}
		
		public function get nodragMode(): Boolean {
			return _nodragMode; 
		}
		
		public function set nodragMode(a_nodragMode: Boolean): void {
			if (_nodragMode != a_nodragMode) {
				_nodragMode = a_nodragMode;
				updateNodragMode();
			}
		}
		
		protected function updateNodragMode(): void {
			_handles.blendMode = _nodragMode?BlendMode.INVERT:BlendMode.NORMAL;
			if (!_nodragMode) updateFromLinkControl();
		}
		
		override protected function listenEvents():void {
			super.listenEvents();
			addEvent(c_events.GETSELECTED, doGetSelect, workspace);
			
			addEvent(uif_component.ENDDRAG, doEndDrag);
			addEvent(uif_component.STARTDRAG, doStartDrag);
			addEvent(uif_component.DRAG, doDragRect);
			addEvent(KeyboardEvent.KEY_DOWN, doKeyDown, stage);

			addEvent(c_uiEvents.TOTOP, doTotop, workspace);
			addEvent(c_uiEvents.TOBOTTOM, doBottom, workspace);
			addEvent(c_uiEvents.REMOVE, doRemoveElement, workspace);

		}
		
		private function doDClick(e: MouseEvent): void {
			if (_link) _link.editMode = true;
		}
		
		private function doGetSelect(e: ObjectEvent): void {
			e.object.result = _link;
		}
		
		protected function doKeyDown(e: KeyboardEvent): void {
			var tf: TextField = e.target as TextField
			if (!tf || (tf.type != TextFieldType.INPUT)) {
				switch (e.keyCode) {
					case Keyboard.LEFT: moveStep(-1, 0);
						break;
					case Keyboard.RIGHT: moveStep(1, 0);
						break;
					case Keyboard.UP: moveStep(0, -1);
						break;
					case Keyboard.DOWN: moveStep(0, 1);
						break;
				}
			}
		}
		
		protected function moveStep(sx: int, sy: int): void {
			setPosition(x + sx, y + sy);
			updateLinkControl();
		}
		
		protected function doTotop(e: Event): void {
			if (_link) {
				_link.toTop();
			}
		}
		
		protected function doBottom(e: Event): void {
			if (_link) {
				_link.toBack();
			}
		}
		
		protected function doMouseDown(e: MouseEvent): void {
			//if (link) editor.checkAndSelectObject(link);
			if (!(e.target is c_dragRectHandle) && !look) {
				var a_element: c_baseElement = editor.hitElement();
				if (a_element) {
					if (a_element != link) {
						if (link is c_bitmapMaskElement) {
							if (a_element.owner != link) a_element.executeMySelect();
							else beginDragRect();
						} else if (link && (a_element is c_holeyElement) && ((a_element as c_holeyElement).holeFocusImage == link)) {
							beginDragRect();
						} else a_element.executeMySelect();
					} else beginDragRect();
				} else executeCommand(new c_linkCommand(this, null));
			}
		}
		
		public function beginDragRect(): void {
			if (!look && visible) beginDrag(2);
		}
		
		private function doStartDrag(e: Event): void {
			startEditing();
		}
		
		private function doEndDrag(e: Event): void {
			endEditing();
		}
		
		protected function doRemoveElement(e: Event): void {
			if (link) {
				if (!nodragMode) executeCommand(new c_deleteCommand(editor, link));
//				else if (link is c_bitmapElement) executeCommand(new c_cropCommand(editor, link as c_bitmapElement, true));
			}
		}
		
/*		
		protected function doMergeImages(e: Event): void {
			if (link) {
				var mergeImage: BitmapData = link.mergeSubs();
				if (mergeImage) {
					var rect: Rectangle = link.getBounds(parent);
					executeCommand(new c_insertBitmapCommand(editor, rect, new Bitmap(mergeImage), true));
				}
			}
		}
*/		
		
		public function startEditing(): void {
			_prevRestoreData = getHistoryData();			
		}
		
		override public function setHistoryData(a_data: Object): void {
			super.setHistoryData(a_data);
		}
		
		public function endEditing(): void {
			if (_prevRestoreData) {
				if (!nodragMode) executeCommand(new c_applyHistoryData(this, getHistoryData(), _prevRestoreData));
				updateLinkControl();
				_prevRestoreData = null;
			}
		}
		
		override protected function createComponents():void {
			_rect = new c_rect(this);
			_rect.cursorName 			= c_cursors.MOVE;
			_rect.doubleClickEnabled 	= true;
			
			_handles = new c_pcomponent(this);
			for (var i: int=0; i < HANDLEDATA.length; i++) {
				var _handle: c_dragRectHandle = new c_dragRectHandle(_handles, HANDLEDATA[i][3], HANDLEDATA[i][2], HANDLEDATA[i][4]);
				_handle.cursorName = HANDLEDATA[i][5];
			}
			
			_rect.addEvent(MouseEvent.MOUSE_DOWN, doMouseDown, editor);
			_rect.addEvent(MouseEvent.DOUBLE_CLICK, doDClick);
		}
		
		public function rollMatrix(angle: Number): void {
			var mat: Matrix = new Matrix();
			var c: Point = center;
			mat.translate(-c.x, -c.y);
			mat.rotate(angle);
			mat.translate(c.x, c.y);
			
			mat.concat(transform.matrix);
			transform.matrix = mat;
			updateLinkControl();
		} 
		
		protected function doDragRect(e: Event): void {
			updateLinkControl();
		}
		
		protected function updateLinkControl(): void {
			if (_link && !_nodragMode) {
				var mat: Matrix = new Matrix();
				mat.scale(width / _linkSize.x, height / _linkSize.y);
				mat.concat(transform.matrix);
				_mySet = true;
				_link.matrix = mat;
				_mySet = false;
			}
		}
		
		public function updateFromLinkControl(): void {
			var mat: Matrix = new Matrix();
			mat.rotate(_link.rotation / 180 * Math.PI);
			mat.translate(_link.x, _link.y);
			transform.matrix = mat;
			updareSizeFromLink();
		}
		
		protected function updareSizeFromLink(): void {
			_linkSize = new Point(_link.width, _link.height); 
			size = new Point(_link.width * _link.scaleX, _link.height * _link.scaleY);
		}
		
		override protected function updateBounds():uif_component {
			super.updateBounds();
			updateHandles();
			updateLinkControl();
			return this;
		}
		
		protected function updateHandles(): void {
			for (var i: int; i<_handles.numChildren; i++) {
				var item: DisplayObject = _handles.getChildAt(i);
				var pos: Point = new Point(width * HANDLEDATA[i][0], height * HANDLEDATA[i][1]);
				item.x = pos.x - item.width / 2;
				item.y = pos.y - item.height / 2;
			}
		}
		
		protected function doAddedLink(e: Event): void {
			visible = true;
		}
		
		protected function doRemovedLink(e: Event): void {
			if (link && (link == e.target)) link = null;
		}
		
		protected function doDisposeLink(e: Event): void {
			link = null;
			//executeCommand(new c_linkCommand(this, null));
		}
		
		private function doLinkResize(e: Event): void {
			updareSizeFromLink();
		}
		
		protected function removeLinkEvents(): void {
			_link.removeEventListener(Event.ADDED, doAddedLink);
			_link.removeEventListener(Event.REMOVED, doRemovedLink);
			_link.removeEventListener(uif_ecomponent.DISPOSE, doDisposeLink);
			_link.removeEventListener(c_baseElement.UPDATEMATRIX, doUpdateMatrix);
			_link.removeEventListener(uif_component.RESIZE, doLinkResize);
		}
		
		protected function addLinkEvents(): void {
			_link.addEvent(Event.ADDED, doAddedLink);
			_link.addEvent(Event.REMOVED, doRemovedLink);
			_link.addEvent(uif_ecomponent.DISPOSE, doDisposeLink);
			_link.addEvent(c_baseElement.UPDATEMATRIX, doUpdateMatrix);
			_link.addEvent(uif_component.RESIZE, doLinkResize);
		}
		
		protected function doUpdateMatrix(e: Event): void {
			if (!_mySet) {
				updateFromLinkControl();
			}
		}
		
		public function executeUnLink(): void {
			if (link && !nodragMode) executeCommand(new c_linkCommand(this, null));
		}
		
		protected function linkComponent(a_component: c_baseElement): void {
			if (_link != a_component) {
				if ((a_component == null) && _link && !_link.parent) {
					return;
				}
				if (look) look = false;
				if (nodragMode) nodragMode = false;
				if (_link) removeLinkEvents();
				_link = a_component;
				
				if (_link) {
					addLinkEvents();
					updateFromLinkControl();
					visible = true;
				} else visible = false;
				workspace.dispatchEvent(new ObjectEvent(c_events.CHANGECURRENTELEMENT, _link));
			}
		}
	}
}